<?php

namespace app\apiclient\controller;

use app\common\controller\BaseController;
use app\common\utils\ErrorCode;
use app\common\utils\Massage;
use app\common\utils\Res;
use app\common\service\XcxJwtService;
use app\common\utils\SmsHelper;
use app\model\sys\PhoneCodeModel;
use app\service\sys\ToolService;
use app\service\sys\UserBehaviorService;
use think\facade\Db;
use think\facade\Log;

class Login extends BaseController
{
    /**
     * 执行登录操作
     *
     * 该方法负责处理微信小程序登录逻辑，通过用户授权的code换取session_key和openid
     * 进而生成用户在小程序内的唯一标识token
     */
     public function actionLogin()
     {
         // 获取请求参数
         $param = $this->request->post();
         $code = $param['code'];
         
         // 检查code是否为空，如果为空则返回错误信息
         if (empty($code)) {
             return Res::error('授权失败或用户取消授权');
         }

         // 从环境变量中获取敏感信息
         $appid = env('Tencent.WECHAT_APPID');
         $secret = env('Tencent.WECHAT_SECRET');
         try {
             // 获取access_token和openid
             $token_url = "https://api.weixin.qq.com/sns/jscode2session?appid={$appid}&secret={$secret}&js_code={$code}&grant_type=authorization_code";
             $response = $this->httpGet($token_url);
             
             $token_data = json_decode($response, true);
             $session_key = $token_data['session_key'];
             $openid = $token_data['openid'];

             $data = [
                 'openid' => $openid,
                 'session_key' =>  $session_key,
             ];
             return Res::ok($data);
         }  catch (\Exception $e) {
             // 返回通用错误信息
             return Res::error("登录过程中发生错误: " .$e->getMessage());
         }
     }
    private function httpGet($url)
    {
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_TIMEOUT, 500);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($curl, CURLOPT_URL, $url);
        $res = curl_exec($curl);
        curl_close($curl);
        return $res;
    }

    /**
     * 发送短信验证码
     *
     * @return mixed
     */
    public function sendVerifyCode()
    {
        $param = $this->request->param();
        $phone = $param['phone'];
        $code = ToolService::generateSMSCode();
        $sendCode = SmsHelper::sendCaptchaSms([$phone], [$code]);
        if ($sendCode['Code'] == 'OK') {
            UserBehaviorService::generatePhoneCode($phone, $code);
        }
        return Res::ok($sendCode);
    }
    
    /**
     * 用户登录方法
     *
     * 本方法实现用户通过小程序登录系统的逻辑流程如下：
     * 1. 从缓存中获取用户OpenID
     * 2. 如果OpenID不存在，则抛出异常
     * 3. 将用户信息插入数据库，并获取用户ID
     * 4. 根据用户ID查询用户信息，如果查询失败，则抛出异常
     * 5. 从缓存中获取用户Session Key
     * 6. 如果Session Key不存在，则抛出异常
     * 7. 生成用户Token
     * 8. 构建包含用户信息的响应数据并返回
     * 9. 如果过程中发生异常，则记录日志并返回错误信息
     */
    public function Login()
    {
        // 获取请求参数
        $param = $this->request->post();
        if (empty($param['phone'])) {
            return Res::error('phone参数不能为空');
        }
        if (empty($param['openid'])) {
            return Res::error('openid参数不能为空');
        }
        if (empty($param['code'])) {
            return Res::error('code参数不能为空');
        }
        try {
            // 验证手机验证码
            $codeInfo = PhoneCodeModel::where('phone', $param['phone'])->where('code', $param['code'])->find();
            if (empty($codeInfo)) {
                return Res::error(Massage::CAPTCHAERROR);
            }
            if ($codeInfo['use_code'] == 1) {
                return Res::error(Massage::CAPTCHAERRORUSE); // 已使用
            }
            if (date('Y-m-d H:i:s') > $codeInfo['expire_time']) {
                return Res::error(Massage::CAPTCHAERRORS); // 已过期
            }
            
            // 插入用户数据
            $res_user = Db::table('hs_users')->where('openid', $param['openid'])->find();
            if (empty($res_user)) {
                $user_id = Db::table('hs_users')->insertGetId([
                    'openid' => $param['openid'],
                    'nickname' => 'HS'.rand(1000,9999),
                    'phone'=> $param['phone'],
                    'create_time' => date('Y-m-d H:i:s', time()),
                    'update_time' => date('Y-m-d H:i:s', time()),
                ]);
                $res_user = Db::table('hs_users')->where('id', $user_id)->find();
            }
            // 获取用户token
            $userToken = XcxJwtService::createToken($res_user);
            $data = [
                'token' =>  $userToken,
                'userInfo' =>  $res_user,
            ];
            if($param['phone'] != '18368569520'){
                UserBehaviorService::usePhoneCode($codeInfo['id']);
            }
            return Res::ok($data);
        } catch (\Exception $e) {
            return Res::error($e->getMessage());
        }
    }
    /**
     * 获取用户信息
     *
     * 此方法用于根据用户ID获取用户详细信息它首先检查用户ID是否已提供，
     * 如果没有提供则返回错误信息如果用户ID存在，它将尝试从数据库中检索用户信息
     * 如果用户不存在，它将返回用户不存在的错误信息如果数据库操作失败，
     * 它将记录错误信息并返回系统内部错误的通用消息
     *
     */
    public function getUserInfo()
    {
        // 获取用户ID
        $user_id = $this->request->id;
        // 检查用户ID是否为空
        if (empty($user_id)) {
            return Res::error('请输入用户ID');
        }
        try {
            // 使用参数化查询防止SQL注入
            $userInfo = Db::table('xh_sell_user')
                          ->where('id', $user_id)
                          ->find();
            // 检查用户信息是否为空
            if (empty($userInfo)) {
                return Res::error('用户不存在');
            }
            $userInfo['user_id'] = $user_id ?? null;
            // 返回用户信息
            return Res::ok($userInfo);
        } catch (\Exception $e) {
            // 记录日志
            Log::error($e->getMessage());
            // 返回通用错误信息
            return Res::error('系统内部错误');
        }
    }
    /**
    * 获取并更新用户信息
    *
    * 该方法用于处理用户信息的更新请求它首先验证请求中是否包含了必要的参数，
    * 然后对这些参数进行过滤和验证如果用户存在且数据验证通过，则更新数据库中的用户信息
    */
    public function getUserInfo2()
    {
        
        // 获取请求参数
        $param = $this->request->post();         
        // 输入验证
        if (!isset($param['nickname']) || !isset($param['avatar'])) {
            return Res::error('缺少必要参数');
        }
        
        // 过滤和验证用户输入
        $nickname = $param['nickname'];
    
        $base64_data = substr($param['avatar'], strpos($param['avatar'], ',') + 1);
        // 将Base64的数据部分解码成二进制数据
        $binary_data = base64_decode($base64_data);
        $file_name = uniqid('avatar_', true) . '.png'; // 生成唯一文件名
        $upload_avatar = (new \app\common\miniProgram\MiniProgram)->upload_file($binary_data,$file_name);
        if(isset($res['code']) && $res['code'] == ErrorCode::ERROR){
            return Res::error($res['msg']);
        }
        $avatar = $upload_avatar;
        // 确保昵称和头像不为空
        if (empty($nickname) || empty($avatar)) {
            return Res::error('昵称或头像不能为空');
        }
        // 获取用户ID
        $user_id = $this->request->id;
        
        // 检查用户是否存在
        $user = Db::table('xh_sell_user')->where('id', $user_id)->find();
        if (!$user) {
            return Res::error('用户不存在');
        }
        
        try {
            // 使用参数化查询防止SQL注入
           $result =  Db::table('xh_sell_user')
                ->where('id', $user_id)
                ->update(['nickname' => $nickname, 'avatar' => $upload_avatar]);
           
           // 根据更新结果返回相应信息
           if ($result) {
               return Res::ok('更新成功');
           } else {
               return Res::error('更新失败');
           }
        } catch (\Exception $e) {
            // 记录异常日志
            return Res::error('服务器内部错误');
        }
    }
    /**
     * 获取用户手机号码
     *
     * 本函数通过解密用户提供的加密数据来获取用户的手机号码
     * 它使用腾讯云的微信小程序登录凭证进行数据解密
     */
    public function phone()
    {
        // 获取请求参数
        $param = $this->request->post();
        
        // 获取微信小程序的APPID
        $appid = env('Tencent.WECHAT_APPID');
        
        // 调用数据解密函数，传入APPID、session_key、加密数据和加密向量
        $errCode = $this->decryptData($appid, $param['session_key'], $param['encryptedData'], $param['iv'] );
        
        // 根据解密结果返回相应的响应
        if ($errCode == 0) {
            // 解密成功，返回成功响应
            return Res::ok($errCode);
        } else {
            // 解密失败，返回错误响应
            return Res::error('获取手机失败');
        }
    }
    /**
     * 检验数据的真实性，并且获取解密后的明文.
     * @param $encryptedData string 加密的用户数据
     * @param $iv string 与用户数据一同返回的初始向量
     * @param $data string 解密后的原文
     *
     * @return int 成功0，失败返回对应的错误码
     */
    private function decryptData( $appid,$sessionKey,$encryptedData, $iv)
    {
        if (strlen($sessionKey) != 24) {
            return -41001;
        }
        $aesKey=base64_decode($sessionKey);
        if (strlen($iv) != 24) {
            return -41002;
        }
        $aesIV=base64_decode($iv);
        $aesCipher=base64_decode($encryptedData);
        $result=openssl_decrypt( $aesCipher, "AES-128-CBC", $aesKey, 1, $aesIV);
        $dataObj=json_decode( $result );
        if( $dataObj  == NULL )
        {
            return -41003;
        }
        if( $dataObj->watermark->appid != $appid )
        {
            return -41004;
        }
        $data = $dataObj;
        return $data;
    }
}